﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Tycho.Compiler;
using Tycho.Parser;
using Tycho.Language;
using Tycho.Runtime;
using Tycho.Lexer;

namespace TychoTest {
    [TestClass]
    public class TestParserLanguage {
        Symbol Tree = Namespaces.Parser.Get ("tree"),
               Name = Namespaces.Parser.Get ("name"),
               MyTree = Namespaces.Parser.Get ("my-tree"),
               Foliage = Namespaces.Parser.Get ("foliage"),
               Branch = Namespaces.Parser.Get ("branch"),
               Leaf = Namespaces.Parser.Get ("leaf"),
               Fruit = Namespaces.Parser.Get ("fruit"),
               Apple = Namespaces.Parser.Get ("apple"),
               Pear = Namespaces.Parser.Get ("pear"),
               Orange = Namespaces.Parser.Get ("orange"),
               Fish = Namespaces.Parser.Get ("fish");

        IParser ForestParser;
        ModuleMap ModuleMap;

        [TestInitialize]
        public void Initialize () {
            ForestParser = GetForestParser ();
            ModuleMap = new ModuleMap (Namespaces.Parser);
        }

        IParser GetForestParser () {
            ParserLanguage plang = new ParserLanguage ();
            string parsersSource =
@"parser forest
    tree ""tree"" name foliage :: foliage
parser foliage
    branch ""{"" foliage "",;"" ... ""}""
    leaf ""leaf""
    fruit ""fruit"" fruit :: fruit
parser fruit
    apple ""apple""
    pear ""pear""
    orange ""orange""
    fish ""fish""
";

            Dictionary<string, IParser> parser = plang.BuildParsers (parsersSource);

            return parser ["forest"];
        }

        Symbol ExpectSymbol (AnyObject term) {
            return ModuleMap.ExpectSymbol (term);
        }

        AnyObject Parse (string source) {
            return ForestParser.Parse (NativeLexer.Lex (source), true);
        }

        [TestMethod]
        public void TestOne () {
            AnyObject treeTerm = Parse (@"tree my-tree fruit apple");

            Assert.AreEqual (Tree, treeTerm [Symbols.ParserTermName]);
            Assert.AreEqual (MyTree, ExpectSymbol (treeTerm [Name]));

            AnyObject foliageTerm = treeTerm [Foliage];

            Assert.AreEqual (Fruit, foliageTerm [Symbols.ParserTermName]);

            AnyObject fruitTerm = foliageTerm [Fruit];
            Assert.AreEqual (Apple, fruitTerm [Symbols.ParserTermName]);
        }

        [TestMethod]
        public void TestTwo () {
            AnyObject treeTerm = Parse (@"tree my-tree { fruit pear, leaf, { leaf, fruit fish }}");

            Assert.AreEqual (Tree, treeTerm [Symbols.ParserTermName]);
            Assert.AreEqual (MyTree, ExpectSymbol (treeTerm [Name]));

            AnyObject foliageTerm = treeTerm [Foliage];

            Assert.AreEqual (Branch, foliageTerm [Symbols.ParserTermName]);

            foliageTerm = foliageTerm [Foliage];
            AnyObject fruitTerm = foliageTerm [0];
            Assert.AreEqual (Fruit, fruitTerm [Symbols.ParserTermName]);
            Assert.AreEqual (Pear, fruitTerm [Fruit] [Symbols.ParserTermName]);
            Assert.AreEqual (Leaf, foliageTerm [1] [Symbols.ParserTermName]);

            AnyObject lastBranchTerm = foliageTerm [2];
            Assert.AreEqual (Branch, lastBranchTerm [Symbols.ParserTermName]);
            foliageTerm = lastBranchTerm [Foliage];
            Assert.AreEqual (Leaf, foliageTerm [0] [Symbols.ParserTermName]);
            fruitTerm = foliageTerm [1];
            Assert.AreEqual (Fruit, fruitTerm [Symbols.ParserTermName]);
            Assert.AreEqual (Fish, fruitTerm [Fruit] [Symbols.ParserTermName]);
        }
    }
}
